package cn.jiaqiang.chatgpt.data.domain.openai.service.channel.model.impl;


import cn.jiaqiang.chatgpt.data.domain.openai.model.aggregates.ChatProcessAggregate;
import cn.jiaqiang.chatgpt.data.domain.openai.service.channel.model.IGenerativeModelService;
import cn.jiaqiang.chatgpt.data.types.enums.ChatGPTModel;
import cn.jiaqiang.chatgpt.data.types.exception.ChatGPTException;
import com.alibaba.fastjson.JSON;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.jiaqiang.chatgpt.common.Constants;
import com.jiaqiang.chatgpt.domain.chat.ChatChoice;
import com.jiaqiang.chatgpt.domain.chat.ChatCompletionRequest;
import com.jiaqiang.chatgpt.domain.chat.ChatCompletionResponse;
import com.jiaqiang.chatgpt.domain.chat.Message;
import com.jiaqiang.chatgpt.session.OpenAiSession;
import lombok.extern.slf4j.Slf4j;
import okhttp3.sse.EventSource;
import okhttp3.sse.EventSourceListener;
import org.apache.commons.lang3.StringUtils;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyEmitter;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @author Fuzhengwei bugstack.cn @小傅哥
 * @description 文本生成
 * @create 2023-11-25 13:56
 */
@Slf4j
@Service
public class TextGenerativeModelServiceImpl implements IGenerativeModelService {

    @Value("${gpt.host:https://api.xty.app/}")
    private String gpt4Host;

    @Value("${gpt.apiKey:sk-r5a1TAwWfea2UqMF69F6A5206cCf40B6866267DcEb3dB0Aa}")
    private String gpt4ApiKey;

    @Resource
    protected OpenAiSession chatGPTOpenAiSession;

    @Override
    public void doMessageResponse(ChatProcessAggregate chatProcess, ResponseBodyEmitter emitter) throws JsonProcessingException {

        String userApiKey = Constants.NULL;
        String userHost = Constants.NULL;

        // 1. 请求消息
        List<Message> messages = chatProcess.getMessages()
                .stream()
                .map(messageEntity -> Message.builder()
                        .role(Constants.Role.valueOf(messageEntity.getRole().toUpperCase()))
                        .content(messageEntity.getContent())
                        .name(messageEntity.getName())
                        .build())
                .collect(Collectors.toList());


        // 2. 封装参数
        ChatCompletionRequest chatCompletion = ChatCompletionRequest
                .builder()
                .stream(true)
                .messages(messages)
                .model(chatProcess.getModel())
                .build();

        // 使用 gpt4
        String model = chatProcess.getModel();
        if (ChatGPTModel.GPT_4.getCode().equals(model) ||
                ChatGPTModel.GPT_4_32K.getCode().equals(model)) {
            userHost = gpt4Host;
            userApiKey = gpt4ApiKey;
        }

        // 3.2 请求应答
        chatGPTOpenAiSession.chatCompletions(userHost, userApiKey, chatCompletion, new EventSourceListener() {
            @Override
            public void onEvent(@NotNull EventSource eventSource, @Nullable String id, @Nullable String type, @NotNull String data) {
                ChatCompletionResponse chatCompletionResponse = JSON.parseObject(data, ChatCompletionResponse.class);
                List<ChatChoice> choices = chatCompletionResponse.getChoices();
                for (ChatChoice chatChoice : choices) {
                    Message delta = chatChoice.getDelta();
                    if (Constants.Role.ASSISTANT.getCode().equals(delta.getRole())) continue;
                    // 应答完成
                    String finishReason = chatChoice.getFinishReason();
                    if (StringUtils.isNoneBlank(finishReason) && "stop".equals(finishReason)) {
                        emitter.complete();
                        break;
                    }
                    // 实时发送信息
                    try {
                        emitter.send(delta.getContent());
                    } catch (Exception e) {
                        throw new ChatGPTException(e.getMessage());
                    }
                }
            }

        });
    }


}
